<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width,user-scalable=no"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
    <meta name="keywords" content="spring-oauth-server,OIDC1.0,OAuth2.1,IAM,IDaaS,WebAuthn"/>
    <meta name="description" content="spring-oauth-server,OIDC1.0,OAuth2.1,IAM,IDaaS,WebAuthn,MKK,monkeyk7,security"/>
    <meta name="author" content="andaily.com"/>
    <link rel="shortcut icon" href="../static/favicon.ico" th:href="@{/favicon.ico}"/>

    <title>client_credentials . spring-oauth-client</title>

    <th:block th:insert="~{fragments/main::header-css}"/>
</head>
<body ng-app>
<div class="container">
    <a th:href="@{/}">Home</a>

    <h2>client_credentials</h2>

    <p>
        grant_type = 'client_credentials' 模式不需要用户去资源服务器登录并授权, 因为客户端(client)已经有了访问资源服务器的凭证(credentials).
        <br/>
        所以当用户访问时,由client直接向资源服务器获取access_token并访问资源即可.
        <br/>
    </p>

    <p class="text-muted">
        若客户端需要登录(或注册), 则用户仅需在客户端登录(或注册)即可,与资源服务器没有关系
    </p>

    <p>
        <small class="text-muted">
            <em class="glyphicon glyphicon-info-sign"></em> 在实际应用中, client_credentials一般都是由后台来完成的,前台没有任何表现,
            常用于子应用中去访问主应用的资源或API(实现服务与服务之间互信).
        </small>
    </p>

    <div>
        <p>在本操作中, 需要client支持<code>client_credentials</code>的grant_type(若不支持请求会失败).</p>
    </div>

    <br/>

    <div ng-controller="ClientCredentialsCtrl">
        <div class="panel panel-default">
            <div class="panel-heading">第一步 <code>获取access_token</code></div>
            <div class="panel-body">
                <div class="col-md-10">
                    <p class="text-muted">
                        点击 '获取access_token' 按钮, 将向spring-auth-server请求获取access_token.
                        <br/>
                        若是开发者关心请求的参数,可点击'显示请求参数' 展示请求的参数细节.
                    </p>

                    <form class="form-horizontal" action="#" onsubmit="return false;">
                        <div class="form-group">
                            <label class="col-sm-2 control-label">accessTokenUri</label>

                            <div class="col-sm-10">
                                <p class="form-control-static"><code>[[${accessTokenUri}]]</code>
                                    &nbsp;<a th:href="${accessTokenUri}" target="_blank">测试连接</a></p>
                            </div>
                        </div>
                        <a href="javascript:void(0);" ng-click="showParams()">显示请求参数</a>

                        <div ng-show="visible">
                            <div class="form-group">
                                <label class="col-sm-2 control-label">client_id</label>

                                <div class="col-sm-10">
                                    <input type="text" class="form-control" name="client_id" required="required"
                                           ng-model="clientId"/>

                                    <p class="help-block">客户端从 spring-oauth-server 申请的client_id, 有的OAuth服务器中又叫
                                        AppKey</p>
                                </div>
                            </div>
                            <div class="form-group">
                                <label class="col-sm-2 control-label">client_secret</label>

                                <div class="col-sm-10">
                                    <input type="text" class="form-control" name="client_secret" required="required"
                                           ng-model="clientSecret"/>

                                    <p class="help-block">客户端从 spring-oauth-server 申请的client_secret, 有的Oauth服务器中又叫
                                        AppSecret</p>
                                </div>
                            </div>
                            <div class="form-group">
                                <label class="col-sm-2 control-label">grant_type</label>

                                <div class="col-sm-10">
                                    <input type="text" class="form-control" name="grant_type" readonly="readonly"
                                           ng-model="grantType"/>

                                    <p class="help-block">固定值 'client_credentials'</p>
                                </div>
                            </div>
                            <div class="form-group">
                                <label class="col-sm-2 control-label">scope</label>

                                <div class="col-sm-10">
                                    <input name="scope" ng-model="scope" class="form-control" readonly
                                           placeholder="openid"/>
                                    <p class="help-block">OIDC标准中定义的scope有: openid, profile, email, address, phone;
                                        具体支持哪些由注册的client决定</p>
                                </div>
                            </div>

                        </div>
                        <br/>
                        <br/>
                        <button class="btn btn-primary" ng-click="getAccessToken()">获取access_token</button>
                        <span class="label label-warning">POST</span>
                    </form>
                </div>
            </div>
        </div>

        <div class="panel panel-default">
            <div class="panel-heading">第二步 <code>访问资源服务器的API</code></div>
            <div class="panel-body">
                <div ng-hide="tokenVisible">请先获取access_token</div>
                <div ng-show="tokenVisible" class="col-md-11">
                    <div class="well well-sm">
                        <dl class="dl-horizontal">
                            <dt>access_token</dt>
                            <dd><textarea rows="5" readonly class="form-control">{{accessToken}}</textarea></dd>
                            <dt>token_type</dt>
                            <dd><code>{{tokenType}}</code></dd>
                            <dt>scope</dt>
                            <dd><code>{{tokenScope}}</code></dd>
                            <dt>expires_in</dt>
                            <dd><code>{{expiresIn}}</code></dd>
                        </dl>
                        <p class="text-danger">{{tokenError}}</p>
                        <p class="help-block">提示: client_credentials 响应中无 id_token与 refresh_token, 若需要, 请使用authorization_code</p>
                    </div>

                    <p>
                        获取access_token成功, 可访问资源服务器开放的API
                    </p>

                    <p class="help-block">spring-oauth-server 中暂无相应的API</p>
                </div>
            </div>
        </div>

        <div class="text-center">
            <a href="javascript:history.back();" class="btn btn-default">返回</a>
        </div>
    </div>

    <script th:inline="javascript">
        var ClientCredentialsCtrl = ['$scope', '$http', function ($scope, $http) {
            $scope.clientId = [[${clientDetails.clientId}]];
            $scope.clientSecret = [[${clientDetails.clientSecret}]];
            $scope.grantType = "client_credentials";

            $scope.scope = [[${clientDetails.scopes}]];
            $scope.visible = false;
            $scope.tokenVisible = false;

            $scope.showParams = function () {
                $scope.visible = !$scope.visible;
            };

            $scope.getAccessToken = function () {
                var uri = "credentials_access_token?clientId=" + $scope.clientId + "&clientSecret=" + $scope.clientSecret + "&grantType=" + $scope.grantType + "&scope=" + $scope.scope
                    + "&accessTokenUri=" + encodeURIComponent([[${accessTokenUri}]]);

                $http.get(uri).success(function (data) {
                    $scope.accessToken = data.accessToken;
                    $scope.tokenType = data.tokenType;

                    $scope.tokenScope = data.scope;
                    $scope.expiresIn = data.expiresIn;
                    //if have error
                    $scope.tokenError = data.error + " " + data.errorDescription;

                    $scope.tokenVisible = true;
                });
            };
        }];
    </script>

    <div th:replace="~{fragments/main :: footer}"/>
</div>
</body>
</html>